package com.hanserwei.han_picture.manager.uploadtemplate;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.hanserwei.han_picture.domain.exception.ApiException;
import com.hanserwei.han_picture.enums.ResponseCodeEnum;
import com.hanserwei.han_picture.utils.ThrowUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Set;

@Slf4j
@Service
public class URLPictureUpload extends PictureUploadTemplate {
    // 允许的图片MIME类型
    private static final Set<String> ALLOWED_CONTENT_TYPES = Set.of(
            "image/jpeg",
            "image/png",
            "image/webp",
            "image/jpg"
    );

    // 允许的最大文件大小 (8MB - 你已经改为8MB了)
    private static final long MAX_FILE_SIZE_BYTES = 8 * 1024 * 1024;

    // 可信域名列表（用于跳过严格验证）
    private static final Set<String> TRUSTED_DOMAINS = Set.of(
            "dashscope-result-wlcb.oss-cn-wulanchabu.aliyuncs.com"
    );

    @Override
    protected <T> void validPicture(T t) {
        String fileUrl = (String) t;
        ThrowUtils.throwIf(StrUtil.isBlank(fileUrl), ResponseCodeEnum.INVALID_PARAMETER, "文件地址不能为空！");

        URL url;
        // 1. 校验文件地址格式，支持URL编码
        try {
            // 先尝试直接解析
            URI uri = new URI(fileUrl);
            url = uri.toURL();
            // 在 validPicture 方法开始处添加
            String host = url.getHost();
            if (host != null && host.contains("aliyuncs.com") && "https".equals(url.getProtocol())) {
                log.info("跳过阿里云OSS验证: {}", host);
                return;
            }
        } catch (Exception e) {
            // 如果直接解析失败，可能是编码问题，记录日志但继续尝试
            log.warn("URI解析失败，尝试直接创建URL: {}", fileUrl);
            try {
                URI uri = new URI(fileUrl);
                url = uri.toURL();
            } catch (Exception ex) {
                throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "文件地址格式错误！");
            }
        }

        // 2. 验证URL协议
        String protocol = url.getProtocol();
        if (!"http".equalsIgnoreCase(protocol) && !"https".equalsIgnoreCase(protocol)) {
            throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "文件地址协议错误！");
        }

        // 3. 检查是否为可信域名，如果是则跳过详细验证
        String host = url.getHost();
        if (TRUSTED_DOMAINS.contains(host)) {
            log.info("跳过详细验证，可信域名: {}", host);
            return;
        }

        // 4. 验证URL是否存在、类型和大小 (HEAD 请求)
        HttpURLConnection connection = null;
        try {
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("HEAD");
            connection.setConnectTimeout(10000); // 增加到10秒连接超时
            connection.setReadTimeout(10000);    // 增加到10秒读取超时

            // 添加User-Agent，避免某些服务器拒绝请求
            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible; han-picture/1.0)");

            int responseCode = connection.getResponseCode();
            log.info("URL验证 - URL: {}, 响应码: {}", fileUrl, responseCode);

            if (responseCode != HttpURLConnection.HTTP_OK) {
                throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "文件不存在或无法访问！响应码: " + responseCode);
            }

            // 校验文件类型 (Content-Type)
            String contentType = connection.getContentType();
            log.info("URL验证 - Content-Type: {}", contentType);

            if (StrUtil.isBlank(contentType)) {
                // 如果没有Content-Type，尝试从URL扩展名判断
                String urlPath = url.getPath().toLowerCase();
                if (urlPath.contains(".jpg") || urlPath.contains(".jpeg")) {
                    contentType = "image/jpeg";
                } else if (urlPath.contains(".png")) {
                    contentType = "image/png";
                } else if (urlPath.contains(".gif")) {
                    contentType = "image/gif";
                } else if (urlPath.contains(".webp")) {
                    contentType = "image/webp";
                } else {
                    log.warn("无法从URL确定文件类型，URL: {}", fileUrl);
                    // 对于无法确定类型的情况，记录警告但允许继续（因为下载时会再次验证）
                    return;
                }
                log.info("从URL路径推断的Content-Type: {}", contentType);
            }

            // 检查Content-Type（忽略字符集等额外参数）
            String mainContentType = contentType.split(";")[0].toLowerCase().trim();
            if (!ALLOWED_CONTENT_TYPES.contains(mainContentType)) {
                throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "文件类型不支持！当前类型: " + mainContentType);
            }

            // 校验文件大小 (Content-Length)
            long contentLength = connection.getContentLengthLong();
            log.info("URL验证 - Content-Length: {}", contentLength);

            if (contentLength > MAX_FILE_SIZE_BYTES) {
                throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER, "文件大小不能超过8MB！当前大小: " + (contentLength / 1024 / 1024) + "MB");
            }

            // 如果Content-Length为-1或0，记录警告但不阻止上传
            if (contentLength <= 0) {
                log.warn("无法获取文件大小，将在下载时验证，URL: {}", fileUrl);
            }

        } catch (SocketTimeoutException e) {
            log.error("连接超时，URL: {}", fileUrl, e);
            throw new ApiException(ResponseCodeEnum.SYSTEM_ERROR, "连接超时，请稍后重试！");
        } catch (IOException e) {
            log.error("网络连接失败，URL: {}", fileUrl, e);
            throw new ApiException(ResponseCodeEnum.SYSTEM_ERROR, "网络连接失败！");
        } catch (ApiException e) {
            // 重新抛出业务异常
            throw e;
        } catch (Exception e) {
            log.error("验证文件地址失败！URL: {}", fileUrl, e);
            throw new ApiException(ResponseCodeEnum.SYSTEM_ERROR, "验证文件地址失败！");
        } finally {
            // 确保资源被释放
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    /**
     * 获取原始文件名
     *
     * @param t url文件链接
     * @return 图片文件名
     */
    @Override
    protected <T> String getOriginalFilename(T t) {
        String fileUrl = (String) t;
        try {
            // 处理URL编码的文件名
            String decodedUrl = URLDecoder.decode(fileUrl, StandardCharsets.UTF_8);
            String fileName = FileUtil.mainName(decodedUrl);

            // 如果解码后的文件名为空，使用原始URL
            if (StrUtil.isBlank(fileName)) {
                fileName = FileUtil.mainName(fileUrl);
            }

            // 如果还是为空，生成默认文件名
            if (StrUtil.isBlank(fileName)) {
                fileName = "image_" + System.currentTimeMillis();
            }

            return fileName;
        } catch (Exception e) {
            log.warn("解析文件名失败，使用默认名称，URL: {}", fileUrl, e);
            return "image_" + System.currentTimeMillis();
        }
    }

    /**
     * 下载文件
     *
     * @param t    url文件链接
     * @param file 文件
     * @param <T>  url文件链接
     * @throws IOException 文件处理异常
     */
    @Override
    protected <T> void processFile(T t, File file) throws IOException {
        String fileUrl = (String) t;
        try {
            // 使用hutool下载文件，设置超时时间
            HttpUtil.downloadFile(fileUrl, file, 30000); // 30秒下载超时

            // 下载完成后验证文件大小
            long fileSize = file.length();
            if (fileSize > MAX_FILE_SIZE_BYTES) {
                // 删除过大的文件
                if (file.exists()) {
                    boolean isFileDeleted = file.delete();
                    if (!isFileDeleted) {
                        log.warn("删除失败，请手动删除！文件路径: {}", file.getAbsolutePath());
                    }
                }
                throw new ApiException(ResponseCodeEnum.INVALID_PARAMETER,
                        "下载的文件大小超过限制！实际大小: " + (fileSize / 1024 / 1024) + "MB");
            }

            log.info("文件下载成功，大小: {}KB, URL: {}", fileSize / 1024, fileUrl);

        } catch (Exception e) {
            log.error("下载文件失败，URL: {}", fileUrl, e);
            // 清理可能部分下载的文件
            if (file.exists()) {
                boolean isFileDeleted = file.delete();
                if (!isFileDeleted) {
                    log.warn("删除临时文件失败，请手动删除！文件路径: {}", file.getAbsolutePath());
                }
            }
            throw new IOException("下载文件失败: " + e.getMessage(), e);
        }
    }
}

